from bson.objectid import ObjectId
from config import *
from utils import *

import sys
import re
import json
import random

sys.path.append('/root/anaconda3/lib/python3.6/site-packages')

import numpy as np


def cos(vector1, vector2):
    dot_product = 0.0
    normA = 0.0
    normB = 0.0

    for a, b in zip(vector1, vector2):
        dot_product += a * b
        normA += a ** 2
        normB += b ** 2

    if normA == 0.0 or normB == 0.0:
        return None
    else:
        return dot_product / ((normA * normB) ** 0.5)


def get_model_vector(query):
    s = np.zeros(200)

    for i in range(5):
        vec = model.infer_vector([word for word, flag in pseg.cut(query) if word not in stoplist and flag not in ['x', 'm']])
        s += vec

    return s / 5


def cos_similarity_calculation(query0, query1):
    if cache.get('cos_similarity_calculation', query0 + '-' + query1):
        return cache.get('cos_similarity_calculation', query0 + '-' + query1)

    scores = []

    for i in range(8):
        scores.append(cos(get_model_vector(query0), get_model_vector(query1)))

    scores.sort(key = lambda i: i)
    scores = scores[1: -1]

    score = sum(scores) / len(scores)

    cache('cos_similarity_calculation', query0 + '-' + query1, score)

    return score


def time():
    return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')


class User():
    def __init__(self, UserID, UserKey):
        self.id = None

        if UserID == '' and UserKey == '':
            return

        UserID, UserKey = str(UserID), str(UserKey)

        # 优先使用UserID识别用户
        if UserID != '0':
            # 如果库里已经有这个用户了，则直接识别这个用户
            if user_log.find_one({'UserID': UserID}):
                user = user_log.find_one({'UserID': UserID})

                self.id = user['_id']
            else:
                # 如果库里有对应UserKey的用户，则说明这个用户在未登陆前已经
                # if user_log.find_one({'UserKey': UserKey}):
                #     self.id = user_log.find_one({'UserKey': UserKey})['_id']
                #     user_log.update_one({'_id': self.id}, {'$set': {'UserID': UserID}})
                # else:

                r = user_log.insert_one({
                    'lastModifiedTime': time(),
                    'UserKey': UserKey,
                    'UserID': UserID,
                    'job_queried': [],
                    'job_viewed': [],
                    'job_delivered': [],
                    'job_collected': [],
                    'labels': [],
                    'evaluation': '',
                    'resume': {}
                })

                self.id = user_log.find_one({'UserID': UserID})['_id']

                # if UserID != '0':
                #     self.id = user_log.find_one({'UserID': UserID})['_id']
                # else:
                #     self.id = user_log.find_one({'UserKey': UserKey})['_id']

            # 同步UserKey
            user_log.update_one({'_id': self.id}, {'$set': {'UserKey': UserKey}})

        elif user_log.find_one({'UserKey': UserKey}):
            user = user_log.find_one({'UserKey': UserKey})

            self.id = user['_id']

        else:
            r = user_log.insert_one({
                'lastModifiedTime': time(),
                'UserKey': UserKey,
                'UserID': UserID,
                'job_queried': [],
                'job_viewed': [],
                'job_delivered': [],
                'job_collected': [],
                'labels': [],
                'evaluation': '',
                'resume': {}
            })

            # self.id = r['inserted_id']
            self.id = user_log.find_one({'UserKey': UserKey})['_id']

    def set_user_resume(self, data):
        """
        记录用户简历内容
        :param data:
        :return:
        """
        for key in data:
            setObj = {}
            setObj['resume.' + key] = data[key]

            user_log.update_one({'_id': self.id}, {'$set': setObj}, True)

    def set_user_evaluation(self, evaluation):
        """
        记录用户的测评数据
        :param data:
        :return:
        """
        user_log.update_one({'_id': self.id}, {'$set': {'evaluation': evaluation}})

    def add_job_queried(self, keyword):
        """
        记录用户查询过的关键字
        :param v:
        :return:
        """
        if not self.id or len(keyword) == 0:
            return

        user_log.update_one({'_id': self.id}, {'$push': {'job_queried': {
            'keyword': keyword,
            'time': time()
        }}})

    def get_job_queried(self):
        if not self.id:
            return []

        user = user_log.find_one({'_id': self.id})

        if not user or not 'job_queried' in user:
            return []

        data = []

        for item in user['job_queried']:
            data.append(item['keyword'])

        return list(set(data))

    def add_job_viewed(self, platform, id):
        """
        记录用户查看过的职位
        :param platform:
        :param id:
        :return:
        """
        if not self.id or not platform or not id:
            return

        user_log.update_one({'_id': self.id}, {'$push': {'job_viewed': {
            'platform': platform,
            'time': time(),
            'id': id
        }}})

    def add_job_delivered(self, platform, id):
        """
        记录用户投递的职位
        :param platform:
        :param id:
        :return:
        """
        if not self.id or not platform or not id:
            return

        user_log.update_one({'_id': self.id}, {'$push': {'job_delivered': {
            'platform': platform,
            'time': time(),
            'id': id
        }}})

    def add_job_collected(self, platform, id, type):
        """
        记录用户收藏的职位
        :param platform:
        :param id:
        :param type:
        :return:
        """

        if not self.id or not platform or not id:
            return

        if type == 1:
            user_log.update_one({'_id': self.id}, {'$push': {'job_collected': {
                'platform': platform,
                'time': time(),
                'id': id
            }}})
        else:
            user = user_log.find_one({'_id': self.id})
            job_collected = [c for c in user['job_collected'] if c['id'] != id]

            user_log.update_one(
                {
                    '_id': self.id
                },
                {
                    '$set': {
                        'job_collected': job_collected
                    }
                }
            )

    def set_labels_selected(self, labels):
        """
        记录用户选择的标签
        :param labels:
        :return:
        """
        if not self.id or not isinstance(labels, list):
            return

        user_log.update_one({'_id': self.id}, {'$set': {'labels': labels}})

    def is_job_collected(self, platform, id):
        """
        查询某个职位是否已收藏
        :param platform:
        :param id:
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        if not user:
            return False

        job_collected = user['job_collected']

        for item in job_collected:
            if item['platform'] == platform and item['id'] == id:
                return True

        return False

    def is_job_delivered(self, platform, id):
        """
        查询某个职位是否已投递
        :param platform:
        :param id:
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        if not user:
            return False

        job_delivered = user['job_delivered']

        for item in job_delivered:
            if item['platform'] == platform and item['id'] == id:
                return True

        return False

    def get_collected_jobs(self):
        """
        获取用户所有的收藏职位
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        job_collected = user['job_collected']

        result = []

        for item in job_collected:
            platform, id = item['platform'], item['id']

            if 'time' in item:
                time = item['time']
            else:
                time = time()

            if not platform in posts_map:
                continue

            job = posts_map[platform].find_one({'_id': ObjectId(id)}, {'_id': 0})
            # job = platform_posts.find_one({'platform': platform, '_id': ObjectId(id)}, {'_id': 0})

            if not job:
                continue

            job['id'] = id
            job['collect_time'] = time

            append_logo_url(job)

            result.append(job)

        return result

    def get_delivered_jobs(self):
        """
        获取用户所有的投递职位
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        job_delivered = user['job_delivered']

        result = []

        for item in job_delivered:
            platform, id = item['platform'], item['id']

            if 'time' in item:
                time = item['time']
            else:
                time = time()

            if not platform in posts_map:
                continue

            job = posts_map[platform].find_one({'_id': ObjectId(id)}, {'_id': 0})
            # job = platform_posts.find_one({'platform': platform, '_id': ObjectId(id)}, {'_id': 0})

            if not job:
                continue

            job['id'] = id
            job['deliver_time'] = time

            append_logo_url(job)

            result.append(job)

        return result

    def matching_degree(self, job_name):
        """
        匹配度打分
        :param job_name:
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        if not user:
            return 0

        if not 'labels' in user and 'evaluation' in user:
            return 0

        if not user['labels'] and not user['evaluation']:
            return 0

        score4label = 0
        score4evalu = 0
        score4major = 0

        # 计算标签与职位的相似度
        if 'labels' in user and user['labels']:
            labels = user['labels']

            score4label = max([cos_similarity_calculation(label, job_name) for label in labels]) / 0.6

            if score4label > 1:
                score4label = 1
        else:
            score4label = 1

        # 计算测评与职位的相似度
        if 'evaluation' in user and user['evaluation']:
            recommend_func = functionals[user['evaluation']]

            score4evalu = max([cos_similarity_calculation(func, job_name) for func in recommend_func]) / 0.6

            if score4evalu > 1:
                score4evalu = 1
        else:
            score4evalu = 1

        return (score4label * 60 + score4evalu * 40) / 100

    def recommond_jobs(self, count):
        """
        职位推荐计算
        :return:
        """
        user = user_log.find_one({'_id': self.id})

        if not user:
            return []

        # 如果没有测评、没有简历则不推荐职位
        if not 'evaluation' in user or not 'resume' in user or not user['resume']:
            return []

        if not user['evaluation']:
            return []

        if not isinstance(user['evaluation'], str):
            return []

        # 获取系统为用户设定的推荐职能
        recommend_func = functionals[user['evaluation']]

        data = []

        for rec in recommend_func:
            for item in knx_qiancheng_position.find({'funca': rec, 'company': {'$in': [re.compile(c) for c in target_enterprise]}}).limit(1):
                data.append(item)

        if len(data) > count:
            data = random.sample(data, count)

        # return data

        # 遍历推荐职能列表，并从库中随机选择一个相应职能的职位
        # for rf in recommend_func:
        #     item = knx_qiancheng_position.find_one({
        #         'funca': rf,
        #         'company':''
        #     })
        #
        #     if item:
        #         data.append(item)
        #
        #     if len(data) == 6:
        #         break

        # for item in data:
        #     if '有限公司' in item['company']:
        #         item['company'] = item['company'][:item['company'].find('有限公司')]

        return data


class JD_FORMAT_CLEAR():
    def __init__(self):
        keywords = """收入及福利待遇 如果你 岗位薪资 工作地点 基本薪资 工作福利 如何面试 薪资情况
        外形要求 外形条件 身高要求 应聘流程 总部地址 地址 入职流程 员工福利 试用期 特别说明 晋升空间 法定假期 
        公司薪酬 均薪 工作地 您即将拥有的 公司待遇 谢绝猎头 薪资待遇 公司福利 地铁 地点 福利体系 上班地点 
        福利及待遇 待遇及福利 公司愿景 条件与要求 晋升体系 总部位于 薪酬福利 其他 晋升序列 上班时间 上班时间
        晋升通道 投递简历 面试地点 工资福利 工作地点 福利待遇 公司福利 工作地址 联系人 岗位待遇 我们提供 发展空间 
        职位申请 地点 保险福利 无责任底薪 培训福利 公司官网 培训流程 其他福利 如何加入 薪酬待遇 所属部门 薪资福利 
        常规福利 招聘流程 招聘流程  聚会 岗位寄语 一经录用 相关福利 为您提供 其他要求 招聘程序 生日会 节日礼物 
        办公环境 工作地址 联系电话 您将享受 月薪 广阔的职业发展空间注意 工作时间 工作时间 办公地址
        作息时间 我们的福利 公司地址 发展方向 职位待遇 为你提供 职务晋升通道 工作时间 联系方式 晋升体制 薪金水平 
        中国最大的 其他要求 简历投递至 津贴 有意者 交通便利 在链家工作 额外福利 期待您的加入 工作区域 预约面试
        联系我们 优先电话 关于我们 应聘电话 薪资 法定节假日 应聘方式 其它福利 公司提供 岗位待遇 基本福利
        PS PS 晋升发展 附 相遇坐标 朝九晚六 电话 周末双休 晋升渠道 面试须知 免费提供 加盟优势 薪资 
        薪资范围 注 高薪福利 薪资福利待遇 你能获得的 应聘邮箱 备注 上海 有意者 公司基本情况 和谐的 我们能提供给您
        你所关心的 岗位晋升 晋升渠道 上班时间 晋升机制 意向加入 觉得合适 看到这里 你将获得 您能获得 晋升方向
        为你提供 我们能给到你 此岗位 职业发展 薪酬标准 广阔的 上班点 杭州市 职业发展路径 收入统计 你努力的回报
        薪酬结构 培训成长 晋升通道 邮箱 薪酬说明 公司位于 接收简历 Address 晋升培训 新人训练 该岗位 注明
        职业薪酬 薪酬体系 丰富的回报 招聘条件 面试时间 工作时间  酬金待遇
        招聘岗位及专业  做什么 职位概要 工作內容 你将 职位总则 我们希望你 职责与权限 你需要做的是
        岗位职能 你要做什么 职责概述 岗位内容 职位职能 我的要求 职位信息 岗位概要 岗位描述 工作要求 职位简介
        职责要求 业务范围 岗位方向 工作职责 负责如下工作 职责描述 职位描述 岗位职责 招聘安排 岗位要求 主要职责 
        你的工作 要做什么事 需要你做什么 工作概述 你要做到 你应该 你要做的事情 这样的你 工作指责 招聘条件
        职资格  任职条件  入职要求 申请条件 任职资格 任职要求 职位要求 招募条件 我们需要你 招聘要求 基本要求
        应聘要求条件 我们希望你是什么样的人 如果你是 需要这样的你 技能要求 招募要求 任职要求 岗位要求
            """.split()

        keywords.sort(key = lambda i: len(i), reverse = True)

        self.keywords = []

        for i in keywords:
            self.keywords.append(('【' + i + '】', i + ':', i + '：'))

    def __call__(self, content):
        content = re.sub('\s{2,}', ' ', content)
        content = re.sub('【】:：', lambda i: '\n\n' + i.group() + '\n\n', content)

        if len(re.split('[一二三四五六七八九十]、', content)) >= 3:
            content = re.sub('[一二三四五六七八九十]、', '', content)

        matched = []

        for kw in self.keywords:
            for k in kw:

                goon = True

                for m in matched:
                    if k in m or m in k:
                        goon = False

                if not goon:
                    continue

                if k in content:
                    content = re.sub(k, lambda i: '\n\n' + i.group() + '\n\n', content)
                    matched.append(k)
                    break

        pattern = ['\d+\.', '•', '- ', '– ', '\d+\)', '\(\d+\)', '\d+、', '· ', '\? ', '\d+，', '\*', '\d+．']

        best_pat = ""
        n = 0

        for p in pattern:
            if len(re.findall(p, content)) > n and len(re.findall(p, content)) >= 3:
                best_pat = p
                n = len(re.findall(p, content))

        if best_pat:
            content = re.sub(best_pat, lambda i: '\n' + i.group(), content)

        content = re.sub('\\n{2,}', '\n\n', content)
        content = re.sub("[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}|\d{11}|\d{3,4}-\d{7,8}", '*' * 8, content)

        return content

# class JD_FORMAT_CLEAR():
#     def __init__(self):
#         valide = """应聘要求 主要工作职责 招聘条件 主要任务和职责 任职基本要求 职位要求 职位简介 工作内容描述 岗位技术要求 任用条件
#                 职位简介 岗位需求 职位要求 Requirements Responsibility REQUIREMENTS 岗位职能 入职要求 职位信息
#                   任职条件 申请条件 岗位概要 岗位描述 工作要求 职位简介 职责要求 业务范围 岗位方向 工作职责
#                  任职资格 任职要求 职位要求 职责描述 职位描述 招募条件 岗位职责 招聘安排 岗位要求 主要职责 职位描述""".split()
#
#         invalide = """薪酬与晋升空间 福利保障  薪资情况 应聘流程 入职流程 特别说明 特色福利 你可以拥有
#                  公司福利 薪资待遇 福利体系 福利及待遇 待遇及福利 公司愿景 条件与要求
#                 薪酬福利 工资福利 福利待遇 公司福利 岗位待遇 职位申请
#                 保险福利 培训福利 薪酬待遇 薪资福利 常规福利 招聘流程 招聘程序
#                 注意： 职位待遇 联系人员 公司福利 备注：""".split()
#
#         self.valide = list(set(valide))
#         self.invalide = list(set(invalide))
#
#         for i in range(len(self.valide)):
#             self.valide.append(self.valide[i] + ':')
#             self.valide.append(self.valide[i] + '：')
#
#         for i in range(len(self.invalide)):
#             self.invalide.append(self.invalide[i] + ':')
#             self.invalide.append(self.invalide[i] + '：')
#
#         self.valide.sort(key = lambda i: len(i), reverse = True)
#         self.invalide.sort(key = lambda i: len(i), reverse = True)
#
#     def __call__(self, content):
#         content = re.sub('【|】|\\n+|:|：', '', content)
#
#         ser_num = ['\(\d+\)\.', '\d{1,2}\.', '\d{1,2}、', '\d{1,2}）', '\d{1,2}\．', '（\d{1,2}）', '\d{1,2}\)', '•', '\d+，']
#
#         for i in ['一、', '二、', '三、', '四、', '五、', '六、', '七、', '八、', '九、', '（一）', '（二）', '（三）', '（四）', '（五）', '（六）', '（七）', '（八）', '（九）', '(一)', '(二)', '(三)', '(四)', '(五)', '(六)', '(七)', '(八)', '(九)']:
#             content = content.replace(i, '')
#
#         for i in re.findall('|'.join(ser_num), content):
#             if int(re.sub("\D", "", i)) > 20:
#                 continue
#
#             if re.sub("\D", "", i)[0] == '0':
#                 continue
#
#             content = content.replace(i, '\n' + '      [' + (re.sub("\D", "", i)) + '] ', 1)
#
#         for item in self.valide:
#             if item in content:
#                 content = content.replace(item, '\n\n' + '【' + item.strip() + '】')
#
#         for item in self.invalide:
#             if item in content:
#                 content = content.replace(item, '\n\n' + '【' + item.strip() + '】')
#                 break
#
#         if content.strip()[0] == '【':
#             content = content.strip()
#
#         return content
